#pragma once

#include "GameObject.h"
#include "Player.h"

class CPlayer;

class CCamera
{
public:
	CCamera(const CCamera *pCamera);
    CCamera();
    ~CCamera();
protected:
    CPlayer						*m_pPlayer;              
    BOUNDINGCUBE				m_bcBoundingCube;               
    D3DXMATRIX					m_mtxView;              
    D3DXMATRIX					m_mtxProjection;              
    D3DXPLANE					m_FrustumPlanes[6];           
    
    bool						m_bViewMatrixDirty;           
    bool						m_bProjectionMatrixDirty;           
    bool						m_bFrustumDirty;        
    
    float						m_fFOV;                 
    float						m_fNearClip;            
    float						m_fFarClip;             
    D3DVIEWPORT9				m_vpViewport;             

    D3DXVECTOR3					m_vPosition;               
    D3DXVECTOR3					m_vRight;             
    D3DXVECTOR3					m_vUp;                
    D3DXVECTOR3					m_vLookAt;   

    void CalculateFrustumPlanes();
public:
    void SetFOV(float fFOV) { m_fFOV = fFOV; m_bProjectionMatrixDirty = true; }
    void SetViewportToDevice(long nLeft, long nTop, long nWidth, long nHeight, float fNearClip, float fFarClip, LPDIRECT3DDEVICE9 pDevice = NULL);
    void SetViewMatrixToDevice(LPDIRECT3DDEVICE9 pD3DDevice);
    void SetProjectionMatrixToDevice(LPDIRECT3DDEVICE9 pD3DDevice);
    float GetFOV() const { return(m_fFOV); }
    float GetNearClip() const { return(m_fNearClip); }
    float GetFarClip() const { return(m_fFarClip); }
    const D3DVIEWPORT9& GetViewport() const { return(m_vpViewport); }
    const D3DXMATRIX& GetProjectionMatrix();    
    const D3DXMATRIX& GetViewMatrix();

	bool GetViewMatrixIsDirty() { return(m_bViewMatrixDirty); }

    CPlayer *GetPlayer() const { return(m_pPlayer); }

    const D3DXVECTOR3& GetPosition() const { return(m_vPosition); }
    const D3DXVECTOR3& GetLookAtVector() const { return(m_vLookAt); }
    const D3DXVECTOR3& GetUpVector () const { return(m_vUp); }
    const D3DXVECTOR3& GetRightVector() const { return(m_vRight); }
    
    void SetBoundingCube(const BOUNDINGCUBE& Volume);
    const BOUNDINGCUBE& GetBoundingCube() const;

    virtual void AttachToPlayer(CPlayer *pPlayer);
    virtual void DetachFromPlayer();
    virtual void SetPosition(const D3DXVECTOR3& vPosition) { m_vPosition = vPosition; m_bViewMatrixDirty = true; m_bFrustumDirty = true; }
    virtual void Move(const D3DXVECTOR3& vShift) { m_vPosition += vShift; m_bViewMatrixDirty = true; m_bFrustumDirty = true; }
    virtual void Rotate(float x, float y, float z) { }
    virtual void Update(float fTimeScale, float fLag) { }
    virtual void SetCameraDetails(const CCamera *pCamera) { }

    virtual DWORD GetCameraMode() const = 0;

    bool IsInFrustum(const D3DXVECTOR3 &vMinimum, const D3DXVECTOR3 &vMaximum);
};

class CFirstPersonCamera : public CCamera
{
public:
    CFirstPersonCamera(const CCamera *pCamera);
    CFirstPersonCamera();

    DWORD GetCameraMode() const { return(FIRST_PERSON_CAMERA); }
    void Rotate(float x, float y, float z);
    void SetCameraDetails(const CCamera *pCamera);
};

class CThirdPersonCamera : public CCamera
{
public:
    CThirdPersonCamera(const CCamera *pCamera);
    CThirdPersonCamera();

    DWORD GetCameraMode() const { return(THIRD_PERSON_CAMERA); }
    void Move(const D3DXVECTOR3& vShift) { };
    void Rotate(float x, float y, float z) { };
    void Update(float fTimeScale, float fLag);
    void SetCameraDetails(const CCamera *pCamera);
    void SetLookAt(const D3DXVECTOR3& vLookAt);
};

class CSpaceShipCamera : public CCamera
{
public:
    CSpaceShipCamera(const CCamera *pCamera);
    CSpaceShipCamera();

    DWORD GetCameraMode() const { return(SPACESHIP_CAMERA); }
    void Rotate(float x, float y, float z);
    void SetCameraDetails(const CCamera *pCamera);
};
